#ifndef YVM_ACCESSFLAG_H
#define YVM_ACCESSFLAG_H

enum class ClassAccess {
    ACC_PUBLIC = 0x0001,
    // Declared public; may be accessed from outside its package.
    ACC_FINAL = 0x0010,
    // Declared final; no subclasses allowed.
    ACC_SUPER = 0x0020,
    // Treat superclass methods specially when invoked by the invokespecial
    // instruction.
    ACC_INTERFACE = 0x0200,
    // Is an interface, not a class.
    ACC_ABSTRACT = 0x0400,
    // Declared abstract; must not be instantiated.
    ACC_SYNTHETIC = 0x1000,
    // Declared synthetic; not present in the source code.
    ACC_ANNOTATION = 0x2000,
    // Declared as an annotation type.
    ACC_ENUM = 0x4000  // Declared as an enum type.
};

enum class MethodAccess {
    ACC_PUBLIC = 0X0001,
    // Declared public; may be accessed from outside its package.
    ACC_PRIVATE = 0X0002,
    // Declared private; accessible only within the defining class.
    ACC_PROTECTED = 0X0004,
    // Declared protected; may be accessed within subclasses.
    ACC_STATIC = 0X0008,
    // Declared static.
    ACC_FINAL = 0X0010,
    // Declared final; must not be overridden.
    ACC_SYNCHRONIZED = 0X0020,
    // Declared synchronized; invocation is wrapped by a monitor use.
    ACC_BRIDGE = 0X0040,
    // A bridge method, generated by the compiler.
    ACC_VARARGS = 0X0080,
    // Declared with variable number of arguments.
    ACC_NATIVE = 0X0100,
    // Declared native; implemented in a language other than Java.
    ACC_ABSTRACT = 0X0400,
    // Declared abstract; no implementation is provided.
    ACC_STRICT = 0X0800,
    // Declared strictfp; floating-point mode is FPstrict.
    ACC_SYNTHETIC =
        0X1000  // Declared synthetic; not present in the source code.
};

enum class FieldAccess {
    ACC_PUBLIC = 0x0001,
    // Declared public; may be accessed from outside its package.
    ACC_PRIVATE = 0x0002,
    // Declared private; usable only within the defining class.
    ACC_PROTECTED = 0x0004,
    // Declared protected; may be accessed within subclasses.
    ACC_STATIC = 0x0008,
    // Declared static.
    ACC_FINAL = 0x0010,
    // Declared final; never directly assigned to after object construction.
    ACC_VOLATILE = 0x0040,
    // Declared volatile; cannot be cached.
    ACC_TRANSIENT = 0x0080,
    // Declared transient; not written or read by a persistent object manager.
    ACC_SYNTHETIC = 0x1000,
    // Declared synthetic; not present in the source code.
    ACC_ENUM = 0x4000  // Declared as an element of an enum.
};

#define IS_FIELD(ACC_NAME)                                      \
    inline bool IS_FIELD_##ACC_NAME(int value) {                \
        return (value & (int)FieldAccess::ACC_##ACC_NAME) != 0; \
    }
#define IS_METHOD(ACC_NAME)                                      \
    inline bool IS_METHOD_##ACC_NAME(int value) {                \
        return (value & (int)MethodAccess::ACC_##ACC_NAME) != 0; \
    }
#define IS_CLASS(ACC_NAME)                                      \
    inline bool IS_CLASS_##ACC_NAME(int value) {                \
        return (value & (int)ClassAccess::ACC_##ACC_NAME) != 0; \
    }

IS_METHOD(PUBLIC)
IS_METHOD(PRIVATE)
IS_METHOD(PROTECTED)
IS_METHOD(STATIC)
IS_METHOD(FINAL)
IS_METHOD(SYNCHRONIZED)
IS_METHOD(BRIDGE)
IS_METHOD(VARARGS)
IS_METHOD(NATIVE)
IS_METHOD(ABSTRACT)
IS_METHOD(STRICT)
IS_METHOD(SYNTHETIC)

IS_FIELD(PUBLIC)
IS_FIELD(PRIVATE)
IS_FIELD(PROTECTED)
IS_FIELD(STATIC)
IS_FIELD(FINAL)
IS_FIELD(VOLATILE)
IS_FIELD(TRANSIENT)
IS_FIELD(SYNTHETIC)
IS_FIELD(ENUM)

IS_CLASS(PUBLIC)
IS_CLASS(FINAL)
IS_CLASS(SUPER)
IS_CLASS(INTERFACE)
IS_CLASS(ABSTRACT)
IS_CLASS(SYNTHETIC)
IS_CLASS(ANNOTATION)
IS_CLASS(ENUM)

#endif  // YVM_ACCESSFLAG_H
